--- 模块功能：FIFO 循环缓冲队列
-- @module socket
-- @author openLuat
-- @license MIT
-- @copyright openLuat
-- @release 2020.03.17
require "utils"
module(..., package.seeall)
local rom = {}
rom.__index = rom
--- 创建一个FLASH FIFO 存储队列
-- @string path: 保存缓冲队列的路径字符串
-- @return obj: 缓冲队列对象
-- @usage local rom = fifo.newRom("/gps_msg")
function newRom(path)
    if type(path) ~= "string" then
        log.error("fifo.newRom:", "Wrong path!")
        return nil
    end
    local queue, qpath = {next = 0, path .. ".1"}, path .. ".queue"
    if io.exists(qpath) then
        queue = io.readFile(qpath):unSerialize()
    else
        io.writeFile(qpath, string.serialize(queue))
    end
    return setmetatable({queue = queue, qpath = qpath, path = path}, rom)
end
--- 将数据压入 Flash 虚拟栈中,最大4K*100条
-- @string path: 创建的虚拟栈路径
-- @param o: 要入栈的lua 基本数据类型
-- @return nil
-- @usage fifo.pushRom("/usr_msg","030405060788888809abcd")
-- @usage fifo.pushRom("/gps_msg",{lng="113.4795685",lat="31.2412402273"})
function rom:push(o)
    if #self.queue > 100 then
        self.queue.next = 0
        os.remove(table.remove(self.queue, 1))
        io.writeFile(self.qpath, string.serialize(self.queue))
    end
    io.writeFile(self.queue[#self.queue], string.serialize(o) .. "\n", "a+b")
    if io.fileSize(self.queue[#self.queue]) > 4096 then
        table.insert(self.queue, self.path .. "." .. (self.queue[#self.queue]:match(self.path .. "%.(%d+)$") + 1))
        io.writeFile(self.qpath, string.serialize(self.queue))
    end
end
--- 将数据从 Flash 虚拟栈中取出,最大4K*100条
-- @string path: 创建的虚拟栈路径
-- @return param: 出栈的lua 基本数据类型
-- @usage local o = fifo.popRom("/usr_msg")
-- @usage fifo.popRom("/gps_msg",{lng="113.4795685",lat="31.2412402273"})
function rom:pop()
    local file, err = io.open(self.queue[1], "rb")
    if file then
        file:seek("set", self.queue.next)
        local str = file:read():unSerialize()
        self.queue.next = file:seek()
        local offset = file:seek("end")
        file:close()
        if self.queue.next == offset then
            self.queue.next = 0
            os.remove(table.remove(self.queue, 1))
            if #self.queue == 0 then
                self.queue = {next = 0, self.path .. ".1"}
            end
        end
        io.writeFile(self.qpath, string.serialize(self.queue))
        return str
    else
        log.error("fifo.popRom:", err)
    end
end
--- 删除缓冲数据,重新初始化队列。
-- @return nil
-- @usage rom:rm()
function rom:rm()
    for i = 1, #self.queue do os.remove(self.queue[i]) end
    self.queue = {next = 0, self.path .. ".1"}
    io.writeFile(self.qpath, string.serialize(self.queue))
    log.info("文件已删除:", self.path)
end
-- ram FIFO 队列部分
local ram = {}
ram.__index = ram
--- 创建一个RAM FIFO 存储队列
-- @return obj: 缓冲队列对象
-- @usage local ram = fifo.newRam()
function newRam()
    return setmetatable({first = 0, last = -1}, ram)
end
--- 压入消息到缓冲队列的尾部
-- @string name: 缓冲队列的名字
-- @return FIFO 第1条消息
-- @usage fifo.readRom("gpsmsg")
function ram:push(val)
    self.last = self.last + 1
    self[self.last] = val
end
--- 取出缓冲队列的首部1条消息
-- @string name: 缓冲队列的名字
-- @return FIFO 第1条消息
-- @usage fifo.readRom("gpsmsg")
function ram:pop()
    if self.first > self.last then
        log.error("ram:pop", "list is empty!")
        return nil
    end
    local val = self[self.first]
    self[self.first] = nil
    self.first = self.first + 1
    return val
end
